home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Extensions / Imaging / PIL / BmpImagePlugin.py < prev    next >
Encoding:
Text File  |  2000-06-23  |  4.5 KB  |  208 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: BmpImagePlugin.py,v 1.1.1.2 1999/01/13 09:39:48 sjoerd Exp $
  4. #
  5. # BMP file handler
  6. #
  7. # Windows (and OS/2) native bitmap storage format.
  8. #
  9. # History:
  10. # 95-09-01 fl    Created
  11. # 96-04-30 fl    Added save
  12. # 97-08-27 fl    Fixed save of 1-bit images
  13. # 98-03-06 fl    Load P images as L where possible
  14. # 98-07-03 fl    Load P images as 1 where possible
  15. # 98-12-29 fl    Handle small palettes
  16. #
  17. # Copyright (c) Secret Labs AB 1997-98.
  18. # Copyright (c) Fredrik Lundh 1995-97.
  19. #
  20. # See the README file for information on usage and redistribution.
  21. #
  22.  
  23.  
  24. __version__ = "0.5"
  25.  
  26.  
  27. import string
  28. import Image, ImageFile, ImagePalette
  29.  
  30.  
  31. #
  32. # --------------------------------------------------------------------
  33. # Read BMP file
  34.  
  35. def i16(c):
  36.     return ord(c[0]) + (ord(c[1])<<8)
  37.  
  38. def i32(c):
  39.     return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
  40.  
  41.  
  42. BIT2MODE = {
  43.     1: ("P", "1"),
  44.     4: ("P", "P;4"),
  45.     8: ("P", "P"),
  46.     24: ("RGB", "BGR")
  47. }
  48.  
  49. def _accept(prefix):
  50.     return prefix[:2] == "BM"
  51.  
  52. class BmpImageFile(ImageFile.ImageFile):
  53.  
  54.     format = "BMP"
  55.     format_description = "Windows Bitmap"
  56.  
  57.     def _bitmap(self, header = 0, offset = 0):
  58.  
  59.     if header:
  60.         self.fp.seek(header)
  61.  
  62.     # CORE/INFO
  63.     s = self.fp.read(4)
  64.     s = s + self.fp.read(i32(s)-4)
  65.  
  66.     if len(s) == 12:
  67.  
  68.         # OS/2 1.0 CORE
  69.         bits = i16(s[10:])
  70.         self.size = i16(s[4:]), i16(s[6:])
  71.         lutsize = 3
  72.         colors = 0
  73.  
  74.     elif len(s) in [40, 64]:
  75.  
  76.         # WIN 3.1 or OS/2 2.0 INFO
  77.         bits = i16(s[14:])
  78.         self.size = i32(s[4:]), i32(s[8:])
  79.         self.info["compression"] = i32(s[16:])
  80.         lutsize = 4
  81.         colors = i32(s[32:])
  82.  
  83.     else:
  84.         raise IOError, "Unknown BMP header type"
  85.  
  86.     if not colors:
  87.         colors = 1 << bits
  88.  
  89.     # MODE
  90.     try:
  91.         self.mode, rawmode = BIT2MODE[bits]
  92.     except KeyError:
  93.         raise IOError, "Unsupported BMP pixel depth"
  94.  
  95.     # LUT
  96.     if self.mode == "P":
  97.             palette = []
  98.             greyscale = 1
  99.         if colors == 2:
  100.         indices = (0, 255)
  101.         else:
  102.         indices = range(colors)
  103.             for i in indices:
  104.                 rgb = self.fp.read(lutsize)[:3]
  105.                 if rgb != chr(i)*3:
  106.                     greyscale = 0
  107.                 palette.append(rgb)
  108.         if greyscale:
  109.         if colors == 2:
  110.             self.mode = "1"
  111.         else:
  112.             self.mode = "L"
  113.         else:
  114.         self.mode = "P"
  115.         self.palette = ImagePalette.raw(
  116.             "BGR", string.join(palette, "")
  117.             )
  118.  
  119.     if not offset:
  120.         offset = self.fp.tell()
  121.  
  122.     self.tile = [("raw",
  123.              (0, 0) + self.size,
  124.              offset,
  125.              (rawmode, ((self.size[0]*bits+31)>>3)&(~3), -1))]
  126.  
  127.     def _open(self):
  128.  
  129.     # HEAD
  130.     s = self.fp.read(14)
  131.     if s[:2] != "BM":
  132.         raise SyntaxError, "Not a BMP file"
  133.     offset = i32(s[10:])
  134.  
  135.     self._bitmap()
  136.  
  137. #
  138. # --------------------------------------------------------------------
  139. # Write BMP file
  140.  
  141. def o16(i):
  142.     return chr(i&255) + chr(i>>8&255)
  143.  
  144. def o32(i):
  145.     return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
  146.  
  147. SAVE = {
  148.     "1": ("1", 1, 2),
  149.     "L": ("L", 8, 256),
  150.     "P": ("P", 8, 256),
  151.     "RGB": ("BGR", 24, 0),
  152. }
  153.  
  154. def _save(im, fp, filename, check=0):
  155.  
  156.     try:
  157.     rawmode, bits, colors = SAVE[im.mode]
  158.     except KeyError:
  159.     raise IOError, "cannot write mode %s as BMP" % im.mode
  160.  
  161.     if check:
  162.     return check
  163.  
  164.     stride = ((im.size[0]*bits+7)/8+3)&(~3)
  165.     header = 40 # or 64 for OS/2 version 2
  166.     offset = 14 + header + colors * 4
  167.     image  = stride * im.size[1]
  168.  
  169.     # bitmap header
  170.     fp.write("BM" +            # file type (magic)
  171.          o32(offset+image) +    # file size
  172.          o32(0) +            # reserved
  173.          o32(offset))        # image data offset
  174.  
  175.     # bitmap info header
  176.     fp.write(o32(header) +        # info header size
  177.          o32(im.size[0]) +        # width
  178.          o32(im.size[1]) +        # height
  179.          o16(1) +            # planes
  180.          o16(bits) +        # depth
  181.          o32(0) +            # compression (0=uncompressed)
  182.          o32(image) +        # size of bitmap
  183.          o32(1) + o32(1) +        # resolution
  184.          o32(colors) +        # colors used
  185.          o32(colors))        # colors important
  186.  
  187.     fp.write("\000" * (header - 40))    # padding (for OS/2 format)
  188.  
  189.     if im.mode == "1":
  190.     for i in (0, 255):
  191.         fp.write(chr(i) * 4)
  192.     elif im.mode == "L":
  193.     for i in range(256):
  194.         fp.write(chr(i) * 4)
  195.     elif im.mode == "P":
  196.     fp.write(im.im.getpalette("RGB", "BGRX"))
  197.  
  198.     ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, stride, -1))])
  199.  
  200. #
  201. # --------------------------------------------------------------------
  202. # Registry
  203.  
  204. Image.register_open(BmpImageFile.format, BmpImageFile, _accept)
  205. Image.register_save(BmpImageFile.format, _save)
  206.  
  207. Image.register_extension(BmpImageFile.format, ".bmp")
  208.